#include "pch.h"
#include "iostream_test.h"

#include <boost/iostreams/device/array.hpp>

#include <boostext/iostreams/bin_stream.hpp>
#include <boostext/iostreams/device/vector.hpp>




void iostream_test::bytestream::operator()()
{
	using namespace boostext::iostreams;

	const std::string write_string   = "a simple string";

	const float  write_float   = 8482.1143f;
	const double write_double  = 3.141598647282;

	const uint64 write_uint64  = 1314421904139124;
	const int64  write_int64   = -374211421;

	const uint32 write_uint32  = 32411243;
	const int32  write_int32   = -422112;

	const uint16 write_uint16  = 12342;
	const int16  write_int16   = -19121;

	const uint8  write_uint8   = 121;
	const int8   write_int8    = -50;

	/**
	* Testcase #1: Writing
	* We will test if writing to the writer is possible and if the offset
	* is incremented as it should be, as well as the size of the writer.
	*/
	std::vector<char> buffer;
	bin_stream<vector> writer( buffer );

	writer << write_string;
	writer << write_float;
	writer << write_double;
	writer << write_uint64;
	writer << write_int64;
	writer << write_uint32;
	writer << write_int32;
	writer << write_uint16;
	writer << write_int16;
	writer << write_uint8;
	writer << write_int8;



	/**
	* Testcase #2: Reading
	*/
	std::string read_string;

	float       read_float;
	double      read_double;

	uint64      read_uint64;
	int64       read_int64;

	uint32      read_uint32;
	int32       read_int32;

	uint16      read_uint16;
	int16       read_int16;

	uint8       read_uint8;
	int8        read_int8;


	array_source src( &buffer.front(), buffer.size() );
	bin_stream<array_source> reader( src );

	// The same using operator >>
	reader >> read_string;
	ASSERT_EQUAL( write_string,  read_string );

	reader >> read_float;
	ASSERT_EQUAL( write_float,   read_float );

	reader >> read_double;
	ASSERT_EQUAL( write_double,  read_double );

	reader >> read_uint64;
	ASSERT_EQUAL( write_uint64,  read_uint64 );

	reader >> read_int64;
	ASSERT_EQUAL( write_int64,   read_int64 );

	reader >> read_uint32;
	ASSERT_EQUAL( write_uint32,  read_uint32 );

	reader >> read_int32;
	ASSERT_EQUAL( write_int32,   read_int32 );

	reader >> read_uint16;
	ASSERT_EQUAL( write_uint16,  read_uint16 );

	reader >> read_int16;
	ASSERT_EQUAL( write_int16,   read_int16 );

	reader >> read_uint8;
	ASSERT_EQUAL( write_uint8,   read_uint8 );

	reader >> read_int8;
	ASSERT_EQUAL( write_int8,    read_int8 );


	/**
	 * Testcase #3: Exceptions
	 */
	ASSERT_THROWS( reader >> read_uint64, boostext::ios_failure );
	ASSERT_THROWS( reader.seek(1, std::ios_base::cur), boostext::out_of_range_exception );
	ASSERT_THROWS( reader.read(&read_int8,50), boostext::ios_failure );

	// Although we triggered alot of exceptions, the device must still be usable
	// try to read the stuff again (only the first few bytes)
	reader.seek(0);
	reader >> read_string;
	ASSERT_EQUAL( write_string,  read_string );

	/**
	 * Testcase #4: Testing more streaming operators.
	 * Especially those ones involving std containers.
	 */
	writer.seek(0);

	std::pair<std::string,int> age( "Age", 55 );
	std::vector<std::string> names; names.push_back( "Bob" ); names.push_back( "Simon" ); names.push_back( "Kirk" ); names.push_back( "Scotty" );
	std::list<double> unnamed; unnamed.push_back( 50.0 ); unnamed.push_back( 10.0 ); unnamed.push_back( 30.0 ); unnamed.push_back( 55.0 );
	std::map<int,std::string> titts; titts[10] = "80 dd"; titts[20] = "75 a"; titts[5] = "70 c";
	std::set<int> numbers; numbers.insert( 50 ); numbers.insert( 10 ); numbers.insert( 20 ); numbers.insert( 30 );
	boost::optional<std::string> opt1( "titties" );
	boost::optional<double> opt2;

	writer << age;
	writer << names;
	writer << unnamed;
	writer << titts;
	writer << numbers;
	writer << opt1;
	writer << opt2;


	reader.open(array_source(&buffer.front(), buffer.size()));
	reader.seek(0);
	std::pair<std::string,int> read_age;
	std::vector<std::string> read_names;
	std::list<double> read_unnamed;
	std::map<int,std::string> read_titts;
	std::set<int> read_numbers;
	boost::optional<std::string> read_opt1;
	boost::optional<double> read_opt2;

	reader >> read_age;
	ASSERT_EQUAL( age.first, read_age.first );
	ASSERT_EQUAL( age.second, read_age.second );

	reader >> read_names;
	ASSERT( names == read_names );

	reader >> read_unnamed;
	ASSERT( unnamed == read_unnamed );

	reader >> read_titts;
	ASSERT( titts == read_titts );

	reader >> read_numbers;
	ASSERT( numbers == read_numbers );

	reader >> read_opt1;
	ASSERT( opt1 == read_opt1 );
	std::string test = read_opt1.get();

	reader >> read_opt2;
	ASSERT( opt2 == read_opt2 );
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void iostream_test::staticbytestream::operator()()
{
	
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void iostream_test::operator()()
{
	bytestream()();
	staticbytestream()();
}
///////////////////////////////////////////////////////////////////////////////////////////////////
